#pragma once

#include <atomic>
#include <iostream>
#include <type_traits>

class SharedWeakCount {
public:
  SharedWeakCount() : strong_count_(0), weak_count_(1) {}
  virtual ~SharedWeakCount() = default;

  void add_shared() { ++strong_count_; }

  void release_shared() {
    if (--strong_count_ == 0) {
      delete_object();
      release_weak();
    }
  }

  void add_weak() { ++weak_count_; }

  void release_weak() {
    if (--weak_count_ == 0) {
      printf("release me\n");
      delete this;
    }
  }

  int use_count() const { return strong_count_; }

  int weak_use_count() const { return weak_count_; }

private:
  virtual void delete_object() = 0;

  int strong_count_;
  int weak_count_;
};

template <typename U> class SharedWeakCountImpl : public SharedWeakCount {
public:
  explicit SharedWeakCountImpl(U *ptr) : ptr_(ptr), SharedWeakCount() {}

  void delete_object() override {
    printf("delete obj\n");
    delete ptr_;
  }

private:
  U *ptr_;
};

template <typename U> class SharedWeakCountImpl<U[]> : public SharedWeakCount {
public:
  explicit SharedWeakCountImpl(U *ptr) : ptr_(ptr), SharedWeakCount() {}

  void delete_object() override {
    printf("delete arr\n");
    delete[] ptr_;
  }

private:
  U *ptr_;
};

template <typename U>
class SharedWeakCountWithDataImpl : public SharedWeakCount {
public:
  template <typename... Args>
  explicit SharedWeakCountWithDataImpl(Args &&...args)
      : data(args...), SharedWeakCount() {}
  U *get_data() { return &data; }

  void delete_object() override {}

private:
  U data;
};

template <typename T> class WeakPtr;

template <typename T> class SharedPtrBase {
  friend class WeakPtr<T>;

public:
  SharedPtrBase() : ptr_(nullptr), count_(nullptr) {}

  SharedPtrBase(T *ptr, SharedWeakCount *count) : ptr_(ptr), count_(count) {
    if (count_) {
      count_->add_shared();
    }
  }

  // 拷贝构造函数
  SharedPtrBase(const SharedPtrBase &other)
      : ptr_(other.ptr_), count_(other.count_) {
    if (count_) {
      count_->add_shared();
    }
  }

  // 移动构造函数
  SharedPtrBase(SharedPtrBase &&other) noexcept
      : ptr_(other.ptr_), count_(other.count_) {
    other.ptr_ = nullptr;
    other.count_ = nullptr;
  }

  // 赋值操作符
  SharedPtrBase &operator=(const SharedPtrBase &other) {
    if (this != &other) {
      reset();
      ptr_ = other.ptr_;
      count_ = other.count_;
      if (count_) {
        count_->add_shared();
      }
    }
    return *this;
  }

  // 移动赋值操作符
  SharedPtrBase &operator=(SharedPtrBase &&other) noexcept {
    if (this != &other) {
      reset();
      ptr_ = other.ptr_;
      count_ = other.count_;
      other.ptr_ = nullptr;
      other.count_ = nullptr;
    }
    return *this;
  }

  // 解引用操作符
  T &operator*() const { return *ptr_; }

  // 指针访问操作符
  T *operator->() const { return ptr_; }

  operator bool() const { return ptr_ != nullptr; }

  // 获取引用计数
  int use_count() const { return count_ ? count_->use_count() : 0; }

  T *get() const { return ptr_; }

  // 重置指针
  void reset() {
    if (count_) {
      count_->release_shared();
    }
    ptr_ = nullptr;
    count_ = nullptr;
  }

  // 析构函数
  ~SharedPtrBase() { reset(); }

protected:
  T *ptr_;
  SharedWeakCount *count_;
};

template <typename T> class SharedPtr : public SharedPtrBase<T> {
public:
  using SharedPtrBase<T>::SharedPtrBase;
  explicit SharedPtr(T *ptr = nullptr)
      : SharedPtrBase<T>(
            ptr, ptr == nullptr ? nullptr : new SharedWeakCountImpl<T>(ptr)) {}

  // 添加 dynamic_pointer_cast 方法
  template <typename U> SharedPtr<U> cast() noexcept {
    if (!this->ptr_) {
      return SharedPtr<U>();
    }

    U *casted_ptr = dynamic_cast<U *>(this->ptr_);
    if (!casted_ptr) {
      return SharedPtr<U>();
    }

    return SharedPtr<U>(casted_ptr, this->count_);
  }
};

template <typename T> class SharedPtr<T[]> : public SharedPtrBase<T> {
public:
  using SharedPtrBase<T>::SharedPtrBase;
  explicit SharedPtr(T *ptr = nullptr)
      : SharedPtrBase<T>(
            ptr, ptr == nullptr ? nullptr : new SharedWeakCountImpl<T[]>(ptr)) {
  }

  // 添加 dynamic_pointer_cast 方法
  template <typename U> SharedPtr<U> cast() noexcept {
    if (!this->ptr_) {
      return SharedPtr<U>();
    }

    U *casted_ptr = dynamic_cast<U *>(this->ptr_);
    if (!casted_ptr) {
      return SharedPtr<U>();
    }

    return SharedPtr<U>(casted_ptr, this->count_);
  }
};

template <typename T> class WeakPtr {
public:
  // 构造函数
  WeakPtr() : ptr_(nullptr), count_(nullptr) {}

  // 从SharedPtr构造
  WeakPtr(const SharedPtr<T> &shared)
      : ptr_(shared.ptr_), count_(shared.count_) {
    if (count_) {
      count_->add_weak();
    }
  }

  // 拷贝构造函数
  WeakPtr(const WeakPtr &other) : ptr_(other.ptr_), count_(other.count_) {
    if (count_) {
      count_->add_weak();
    }
  }

  // 移动构造函数
  WeakPtr(WeakPtr &&other) noexcept : ptr_(other.ptr_), count_(other.count_) {
    other.ptr_ = nullptr;
    other.count_ = nullptr;
  }

  // 赋值操作符
  WeakPtr &operator=(const WeakPtr &other) {
    if (this != &other) {
      reset();
      ptr_ = other.ptr_;
      count_ = other.count_;
      if (count_) {
        count_->add_weak();
      }
    }
    return *this;
  }

  // 移动赋值操作符
  WeakPtr &operator=(WeakPtr &&other) noexcept {
    if (this != &other) {
      reset();
      ptr_ = other.ptr_;
      count_ = other.count_;
      other.ptr_ = nullptr;
      other.count_ = nullptr;
    }
    return *this;
  }

  // 获取引用计数
  int use_count() const { return count_ ? count_->use_count() : 0; }

  // 检查是否为空
  bool expired() const { return use_count() == 0; }

  // 尝试提升为SharedPtr
  SharedPtr<T> lock() const {
    if (expired()) {
      return SharedPtr<T>();
    }
    return SharedPtr<T>(ptr_, count_);
  }

  // 重置指针
  void reset() {
    if (count_) {
      count_->release_weak();
    }
    ptr_ = nullptr;
    count_ = nullptr;
  }

  // 析构函数
  ~WeakPtr() { reset(); }

private:
  T *ptr_;
  SharedWeakCount *count_;
};

template <typename T, typename... Args>
SharedPtr<T> MakeShared(Args &&...args) {
  auto count = new SharedWeakCountWithDataImpl<T>(std::forward<Args>(args)...);
  auto data = count->get_data();
  return SharedPtr<T>(data, count);
}

class NonCopyable {
public:
  NonCopyable() = default;
  NonCopyable(const NonCopyable &) = delete;
  NonCopyable &operator=(const NonCopyable &) = delete;
  virtual ~NonCopyable() = default;
};

template <typename FunctionType> class ScopeGuardImpl : public NonCopyable {
public:
  ScopeGuardImpl(FunctionType &&function) noexcept
      : function_(std::move(function)) {}

  ScopeGuardImpl(ScopeGuardImpl &&other) noexcept
      : function_(std::move(other.function_)) {
    other.dismiss();
  }

  ScopeGuardImpl &operator=(ScopeGuardImpl &&other) noexcept {
    function_ = std::move(other.function_);
    other.dismiss();
    return *this;
  }

  void dismiss() noexcept { dismissed_ = true; }

  void rehire() noexcept { dismissed_ = false; }

  void exec() noexcept { function_(); }

  virtual ~ScopeGuardImpl() noexcept {
    if (!dismissed_) {
      function_();
    }
  }

private:
  bool dismissed_{false};
  FunctionType function_;
};

template <typename FunctionType>
ScopeGuardImpl<FunctionType> MakeGuard(FunctionType &&function) noexcept {
  return ScopeGuardImpl<FunctionType>(std::forward<FunctionType>(function));
}